#pragma once
#include "Thread.hpp"
#include "Log.hpp"
#include <vector>
#include <functional>
#include <queue>
#include <unistd.h>

using namespace hcc;
using namespace ThreadMoudle;
const int gdefaultnum = 10;
template <class T>
class ThreadPool
{
    //将加锁和解锁封装为函数
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    //唤醒所有线程或者单个线程
    void Wake()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    //判断任务列表中还有没有任务
    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    //条件变量等待
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    //构造线程池，初始化
    ThreadPool(int thread_num = gdefaultnum) : _thread_num(thread_num), _isrunning(true), _sleep_thread_num(0)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    //处理任务函数
    void HandlerTask(const std::string &name)
    {
        while (true)
        {
            LockQueue();
            while (IsEmpty() && _isrunning)
            {
                //没有任务等待任务到来，被唤醒后去执行任务
                _sleep_thread_num++;
                Sleep();
                _sleep_thread_num--;
            }
            if (!IsEmpty() && !_isrunning) // 处理有任务，但是没有执行的情况
            {  
                UnLockQueue();
                std::cout << name << " quit" << "\n";
                break;
            }
            // 处理任务
            // std::cout << name << " 处理任务" << "\n";
            LOG(INFO,"%s 正在处理任务\n",name.c_str());
            T task;
            task = _task_queue.front();
            _task_queue.pop();
            task();
            UnLockQueue();
        }
    }
    //初始化创建 _thread_num 个线程，并用vector管理起来
    void init()
    {
        func_t func = std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1);
        for (int i = 0; i < _thread_num; i++)
        {
            std::string name = "thread - " + std::to_string(i + 1);
            _threads.emplace_back(name, func);
            LOG(DEBUG,"thread - %d  create success\n",i);
        }
        Start();
    }
    //private里面放了构造函数。这里给单例模式提供了条件
public:
    //放任务到任务列表
    void Equeue(T &in)
    {
        LockQueue();
        if (_isrunning)
        {
            _task_queue.push(in);
            std::cout << "make a data" << "\n";
            std::cout << _task_queue.size() << std::endl;
            if (_sleep_thread_num > 0)
                Wake();
        }
        UnLockQueue();
    }
    //将所有线程都启动
    void Start()
    {
        _isrunning = true;
        for (auto &thread : _threads) // 这里不加引用的话可能会乱码
        {
            thread.Start();
        }
    }
    //停止所有线程
    void Stop()
    {
        LockQueue();
        _isrunning = false;
        WakeAll();
        std::cout << "_sleep_thread_num " << _sleep_thread_num << "\n";
        UnLockQueue();
        std::cout << "Stop all thread" << std::endl;
        LOG(INFO,"threadpool heve stop excute\n");
    }

    //懒汉方式设计单例模式
    static ThreadPool<T>*GetInstance()
    {
        if(_tp==nullptr)
        {
            //加一把锁防止同时两个线程都去创建线程池
            //这里用一个类来封装该锁
            LockGuard lockguard(&_sig_mutex);
            if(_tp==nullptr)
            {
                _tp=new ThreadPool();
                _tp->init();
                _tp->Start();
                LOG(DEBUG,"Create a new threadpool\n");
            }
            //已经创建了一个线程了，就返回该线程
            else 
            {
                LOG(WARNING,"already have a threadpool\n ");
            }
        }
        return _tp;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    //单例模式要把构造和赋值构造删除或者私有化
    ThreadPool(const ThreadPool<T>&)=delete;
    void operator=(const ThreadPool<T>&)=delete;
private:
    int _thread_num;    // 线程个数
    std::vector<Thread> _threads; //管理线程的结构
    std::queue<T> _task_queue;  //任务列表 用队列保存
    bool _isrunning;    //判断线程是否工作

    int _sleep_thread_num;  //休眠线程个数

    pthread_mutex_t _mutex; //互斥锁
    pthread_cond_t _cond;   //条件变量

        //单例模式
    static ThreadPool<T> *_tp;
    static pthread_mutex_t _sig_mutex; //给单例模式设计的锁
};

//类的静态成员要在类外初始化——const成员要在初始化列表初始化
template<class T>
ThreadPool<T>*ThreadPool<T>::_tp=nullptr;

//单例模式的锁不能在构造函数初始化，只能在外面初始化
template<class T>
pthread_mutex_t ThreadPool<T>::_sig_mutex=PTHREAD_MUTEX_INITIALIZER;
